import { useMemo, useState, useCallback, useEffect, useRef, Fragment } from "react" // kilocode_change Fragment
import { VSCodeLink } from "@vscode/webview-ui-toolkit/react"
import { Trans } from "react-i18next"
import { ChevronsUpDown, Check, X } from "lucide-react"

import type { ProviderSettings, ModelInfo, OrganizationAllowList } from "@roo-code/types"

import { useAppTranslation } from "@src/i18n/TranslationContext"
import { useSelectedModel } from "@/components/ui/hooks/useSelectedModel"
// import { filterModels } from "./utils/organizationFilters" // kilocode_change: not doing this
import { cn } from "@src/lib/utils"
import {
	Command,
	CommandEmpty,
	CommandGroup,
	CommandInput,
	CommandItem,
	CommandList,
	Popover,
	PopoverContent,
	PopoverTrigger,
	Button,
	SelectSeparator, // kilocode_change
} from "@src/components/ui"

import { ModelInfoView } from "./ModelInfoView"
import { ApiErrorMessage } from "./ApiErrorMessage"

type ModelIdKey = keyof Pick<
	ProviderSettings,
	| "glamaModelId"
	| "openRouterModelId"
	| "unboundModelId"
	| "requestyModelId"
	| "openAiModelId"
	| "litellmModelId"
	| "kilocodeModel"
>

interface ModelPickerProps {
	defaultModelId: string
	models: Record<string, ModelInfo> | null
	modelIdKey: ModelIdKey
	serviceName: string
	serviceUrl: string
	apiConfiguration: ProviderSettings
	setApiConfigurationField: <K extends keyof ProviderSettings>(field: K, value: ProviderSettings[K]) => void
	organizationAllowList: OrganizationAllowList
	errorMessage?: string
}

export const ModelPicker = ({
	defaultModelId,
	models,
	modelIdKey,
	serviceName,
	serviceUrl,
	apiConfiguration,
	setApiConfigurationField,
	// organizationAllowList, // kilocode_change: unused
	errorMessage,
}: ModelPickerProps) => {
	const { t } = useAppTranslation()

	const [open, setOpen] = useState(false)
	const [isDescriptionExpanded, setIsDescriptionExpanded] = useState(false)
	const isInitialized = useRef(false)
	const searchInputRef = useRef<HTMLInputElement>(null)
	const selectTimeoutRef = useRef<NodeJS.Timeout | null>(null)
	const closeTimeoutRef = useRef<NodeJS.Timeout | null>(null)

	const modelIds = useMemo(() => {
		if (!models) return []

		// kilocode_change begin
		// Sort models by preferredIndex first, then alphabetically
		const preferredModelIds = []
		const restModelIds = []
		// first add the preferred models
		for (const [key, model] of Object.entries(models)) {
			if (model.preferredIndex !== undefined && model.preferredIndex !== null) {
				preferredModelIds.push(key)
			}
		}
		preferredModelIds.sort((a, b) => {
			const modelA = models[a]
			const modelB = models[b]
			return (modelA.preferredIndex ?? 0) - (modelB.preferredIndex ?? 0)
		})

		// then add the rest
		for (const [key] of Object.entries(models)) {
			if (!preferredModelIds.includes(key)) {
				restModelIds.push(key)
			}
		}
		restModelIds.sort((a, b) => a.localeCompare(b))

		const combinedModelIds = [...preferredModelIds, ...restModelIds]
		return combinedModelIds
		// kilocode_change end
	}, [models])

	const { id: selectedModelId, info: selectedModelInfo } = useSelectedModel(apiConfiguration)

	const [searchValue, setSearchValue] = useState("") // kilocode_change

	const onSelect = useCallback(
		(modelId: string) => {
			if (!modelId) {
				return
			}

			setOpen(false)
			setApiConfigurationField(modelIdKey, modelId)

			// Clear any existing timeout
			if (selectTimeoutRef.current) {
				clearTimeout(selectTimeoutRef.current)
			}

			// Delay to ensure the popover is closed before setting the search value.
			selectTimeoutRef.current = setTimeout(() => setSearchValue(""), 100) // kilocode_change: reset value on select
		},
		[modelIdKey, setApiConfigurationField],
	)

	const onOpenChange = useCallback(
		(open: boolean) => {
			setOpen(open)

			// Abandon the current search if the popover is closed.
			if (!open) {
				// Clear any existing timeout
				if (closeTimeoutRef.current) {
					clearTimeout(closeTimeoutRef.current)
				}

				// Clear the search value when closing instead of prefilling it
				closeTimeoutRef.current = setTimeout(() => setSearchValue(""), 100) // kilocode_change: reset value on select
			}
		},
		[] /* kilocode_change */,
	)

	const onClearSearch = useCallback(() => {
		setSearchValue("")
		searchInputRef.current?.focus()
	}, [])

	useEffect(() => {
		if (!selectedModelId && !isInitialized.current) {
			const initialValue =
				selectedModelId && modelIds.includes(selectedModelId) ? selectedModelId : defaultModelId
			setApiConfigurationField(modelIdKey, initialValue)
		}

		isInitialized.current = true
	}, [modelIds, setApiConfigurationField, modelIdKey, selectedModelId, defaultModelId])

	// Cleanup timeouts on unmount to prevent test flakiness
	useEffect(() => {
		return () => {
			if (selectTimeoutRef.current) {
				clearTimeout(selectTimeoutRef.current)
			}
			if (closeTimeoutRef.current) {
				clearTimeout(closeTimeoutRef.current)
			}
		}
	}, [])

	return (
		<>
			<div>
				<label className="block font-medium mb-1">{t("settings:modelPicker.label")}</label>
				<Popover open={open} onOpenChange={onOpenChange}>
					<PopoverTrigger asChild>
						<Button
							variant="combobox"
							role="combobox"
							aria-expanded={open}
							className="w-full justify-between"
							data-testid="model-picker-button">
							<div>{selectedModelId ?? t("settings:common.select")}</div>
							<ChevronsUpDown className="opacity-50" />
						</Button>
					</PopoverTrigger>
					<PopoverContent className="p-0 w-[var(--radix-popover-trigger-width)]">
						<Command>
							<div className="relative">
								<CommandInput
									ref={searchInputRef}
									value={searchValue}
									onValueChange={setSearchValue}
									placeholder={t("settings:modelPicker.searchPlaceholder")}
									className="h-9 mr-4"
									data-testid="model-input"
								/>
								{searchValue.length > 0 && (
									<div className="absolute right-2 top-0 bottom-0 flex items-center justify-center">
										<X
											className="text-vscode-input-foreground opacity-50 hover:opacity-100 size-4 p-0.5 cursor-pointer"
											onClick={onClearSearch}
										/>
									</div>
								)}
							</div>
							<CommandList>
								<CommandEmpty>
									{searchValue && (
										<div className="py-2 px-1 text-sm">
											{t("settings:modelPicker.noMatchFound")}
										</div>
									)}
								</CommandEmpty>
								<CommandGroup>
									{/* kilocode_change start */}
									{modelIds.map((model, i) => {
										const isPreferred = models?.[model]?.preferredIndex !== null
										const previousModelWasPreferred =
											models?.[modelIds[i - 1]]?.preferredIndex !== null

										return (
											<Fragment key={model}>
												{!isPreferred && previousModelWasPreferred ? <SelectSeparator /> : null}
												<CommandItem
													value={model}
													onSelect={onSelect}
													data-testid={`model-option-${model}`}
													className={cn(isPreferred ? "font-semibold" : "")}>
													{model}
													<Check
														className={cn(
															"size-4 p-0.5 ml-auto",
															model === selectedModelId ? "opacity-100" : "opacity-0",
														)}
													/>
												</CommandItem>
											</Fragment>
										)
									})}
									{/* kilocode_change end */}
								</CommandGroup>
							</CommandList>
							{searchValue && !modelIds.includes(searchValue) && (
								<div className="p-1 border-t border-vscode-input-border">
									<CommandItem data-testid="use-custom-model" value={searchValue} onSelect={onSelect}>
										{t("settings:modelPicker.useCustomModel", { modelId: searchValue })}
									</CommandItem>
								</div>
							)}
						</Command>
					</PopoverContent>
				</Popover>
			</div>
			{errorMessage && <ApiErrorMessage errorMessage={errorMessage} />}
			{selectedModelId && selectedModelInfo && (
				<ModelInfoView
					apiProvider={apiConfiguration.apiProvider}
					selectedModelId={selectedModelId}
					modelInfo={selectedModelInfo}
					isDescriptionExpanded={isDescriptionExpanded}
					setIsDescriptionExpanded={setIsDescriptionExpanded}
				/>
			)}
			<div className="text-sm text-vscode-descriptionForeground">
				<Trans
					i18nKey="settings:modelPicker.automaticFetch"
					components={{
						serviceLink: <VSCodeLink href={serviceUrl} className="text-sm" />,
						defaultModelLink: <VSCodeLink onClick={() => onSelect(defaultModelId)} className="text-sm" />,
					}}
					values={{ serviceName, defaultModelId }}
				/>
			</div>
		</>
	)
}
